/**
 * 文件名：MySingleExecutor.java
 *
 * 创建人：Elvin Zhao - 279152260@qq.com
 *
 * 创建时间：2019年5月23日 下午4:04:07
 *
 * 版权所有：FNII
 */
package com.z100h.supplychain.common.service;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.stereotype.Component;

/**
 * 
 * [描述信息：说明类的基本功能]
 *
 * @author Elvin Zhao - 279152260@qq.com
 * @version 1.0 Created on 2019年5月24日 下午2:47:22
 */
@Component
public class MyMultiExecutor {

	private final static int DEFAULT_CORE_SIZE = Runtime.getRuntime().availableProcessors() * 2;

	private final ExecutorService executor;

	private final ConcurrentHashMap<String, List<Future<?>>> resultMap = new ConcurrentHashMap<String, List<Future<?>>>(
			128);

	public MyMultiExecutor(final int coreSize, final String threadName) {
		executor = Executors.newFixedThreadPool(coreSize < DEFAULT_CORE_SIZE ? DEFAULT_CORE_SIZE : coreSize,
				new ThreadFactory() {

					private final AtomicInteger threadNum = new AtomicInteger(1);

					@Override
					public Thread newThread(Runnable runnable) {
						return new Thread(runnable, threadName + threadNum.getAndIncrement());
					}
				});
	}

	public MyMultiExecutor() {
		final int coreSize = 16;
		final String threadName = "defaultExecutor";
		executor = Executors.newFixedThreadPool(coreSize < DEFAULT_CORE_SIZE ? DEFAULT_CORE_SIZE : coreSize,
				new ThreadFactory() {

					private final AtomicInteger threadNum = new AtomicInteger(1);

					@Override
					public Thread newThread(Runnable runnable) {
						return new Thread(runnable, threadName + threadNum.getAndIncrement());
					}
				});
	}

	public Future<?> submit(String category, Runnable runnable) {
		Future<?> future = this.executor.submit(runnable);
		this.resultMap.putIfAbsent(category, new CopyOnWriteArrayList<Future<?>>());
		List<Future<?>> resultsWithCa = this.resultMap.get(category);
		resultsWithCa.add(future);
		return future;
	}

	public void execute(Runnable runnable) {
		this.executor.execute(runnable);
	}

	public boolean waitUntilDone(String category) {
		List<Future<?>> futures = this.resultMap.get(category);
		if (futures == null || futures.size() == 0) {
			return true;
		}
		return waitUntilAllDone(futures, category);
	}

	private boolean waitUntilAllDone(List<Future<?>> futures, String category) {

		for (Future<?> future : futures) {
			while (true) {
				if (future.isCancelled()) {
					break;
				} else {
					if (future.isDone()) {
						break;
					}
				}
			}
		}
		this.resultMap.remove(category);
		return true;
	}

	public void destroy() {
		executor.shutdown();
	}

}
